<?php

defined('SYSPATH') or die('Access error!');

/**
 * 数组助手
 */
class Arr
{

    public static $delimiter = '.';

    /**
     * 检查一个数组是否有映射关系
     *
     *     // 返回true
     *     Arr::is_assoc(array('username' => 'john.doe'));
     *
     *     //  返回 FALSE
     *     Arr::is_assoc('foo', 'bar');
     *
     * @param   array   
     * @return  boolean
     */
    public static function is_assoc(array $array)
    {
        $keys = array_keys($array);

        return array_keys($keys) !== $keys;
    }

    /**
     * 检查 所给的变量是否为一个数组
     * @param   mixed   $value 
     * @return  boolean
     */
    public static function is_array($value)
    {
        if (is_array($value))
        {
            return TRUE;
        }
        else
        {
            return (is_object($value) AND $value instanceof Traversable);
        }
    }

    /**
     * 用所给你的数组填充一个数组
     *
     *     // F生成一个列表 5, 10, 15, 20
     *     $values = Arr::range(5, 20);
     *
     * @param   integer $step   
     * @param   integer $max   
     * @return  array
     */
    public static function range($step = 10, $max = 100)
    {
        if ($step < 1)
            return array();

        $array = array();
        for ($i = $step; $i <= $max; $i += $step)
        {
            $array[$i] = $i;
        }

        return $array;
    }

    /**
     *  获取一个数组的
     *     $username = Arr::get($_POST, 'username');
     *     $sorting = Arr::get($_GET, 'sorting');
     *
     * @param   array   $array
     * @param   string  $key     
     * @param   mixed   $default
     * @return  mixed
     */
    public static function get($array, $key, $default = NULL)
    {
        return isset($array[$key]) && !empty($array[$key]) ? trim($array[$key]) : $default;
    }

    /**
     *  获取多个值
     *     // 从数组中获取 "username", "password"
     *     $auth = Arr::extract($_POST, array('username', 'password'));
     *
     * @param   array   $array 
     * @param   array   $keys 
     * @param   mixed   $default
     * @return  array
     */
    public static function extract($array, array $keys, $default = NULL)
    {
        $found = array();
        foreach ($keys as $key)
        {
            $found[$key] = isset($array[$key]) ? $array[$key] : $default;
        }

        return $found;
    }

    /**
     *  把一个多字段数组 过去其中的一个字段生成一个数组
     *     // 获取$result 中id的值
     *     $ids = Arr::pluck($result, 'id');
     */
    public static function pluck($array, $key)
    {
        $values = array();

        foreach ($array as $row)
        {
            if (isset($row[$key]))
            {
                $values[] = $row[$key];
            }
        }

        return $values;
    }

    /**
     *   一个关联数组的开头添加一个值.
     *
     *     // 选择列表中添加一个空值的开始
     *     Arr::unshift($array, 'none', 'Select a value');
     *
     * @param   array   $array
     * @param   string  $key
     * @param   mixed   $val
     * @return  array
     */
    public static function unshift(array & $array, $key, $val)
    {
        $array = array_reverse($array, TRUE);
        $array[$key] = $val;
        $array = array_reverse($array, TRUE);

        return $array;
    }

    /**
     *  对数组中的值进行调用指定函数
     *
     *     // 为数组 调用"strip_tags"函数
     *     $array = Arr::map('strip_tags', $array);
     *
     *     //为数组调用 $this->filter 
     *     $array = Arr::map(array(array($this,'filter')), $array);
     *
     *     // 同时为数组调用：strip_tags and $this->filter
     *     $array = Arr::map(array('strip_tags',array($this,'filter')), $array);
     */
    public static function map($callbacks, $array, $keys = NULL)
    {
        foreach ($array as $key => $val)
        {
            if (is_array($val))
            {
                $array[$key] = Arr::map($callbacks, $array[$key]);
            }
            elseif (!is_array($keys) or in_array($key, $keys))
            {
                if (is_array($callbacks))
                {
                    foreach ($callbacks as $cb)
                    {
                        $array[$key] = call_user_func($cb, $array[$key]);
                    }
                }
                else
                {
                    $array[$key] = call_user_func($callbacks, $array[$key]);
                }
            }
        }

        return $array;
    }

    /**
     *   合并两个数组 
     *     $john = array('name' => 'john', 'children' => array('fred', 'paul', 'sally', 'jane'));
     *     $mary = array('name' => 'mary', 'children' => array('jane'));
     *     $john = Arr::merge($john, $mary);
     *     array('name' => 'mary', 'children' => array('fred', 'paul', 'sally', 'jane'))
     * @param array $a1
     * @param array $a2
     * @return type 
     */
    public static function merge(array $a1, array $a2)
    {
        $result = array();
        for ($i = 0, $total = func_num_args(); $i < $total; $i++)
        {
            $arr = func_get_arg($i);

            $assoc = Arr::is_assoc($arr);

            foreach ($arr as $key => $val)
            {
                if (isset($result[$key]))
                {
                    if (is_array($val) AND is_array($result[$key]))
                    {
                        if (Arr::is_assoc($val))
                        {
                            $result[$key] = Arr::merge($result[$key], $val);
                        }
                        else
                        {
                            $diff = array_diff($val, $result[$key]);

                            $result[$key] = array_merge($result[$key], $diff);
                        }
                    }
                    else
                    {
                        if ($assoc)
                        {
                            $result[$key] = $val;
                        }
                        elseif (!in_array($val, $result, TRUE))
                        {
                            $result[] = $val;
                        }
                    }
                }
                else
                {
                    $result[$key] = $val;
                }
            }
        }

        return $result;
    }

    /**
     * 第一个数组覆盖第二个数组
     *     $a1 = array('name' => 'john', 'mood' => 'happy', 'food' => 'bacon');
     *     $a2 = array('name' => 'jack', 'food' => 'tacos', 'drink' => 'beer');
     *     $array = Arr::overwrite($a1, $a2);
     *     array('name' => 'jack', 'mood' => 'happy', 'food' => 'tacos')
     * @param type $array1
     * @param type $array2
     * @return type 
     */
    public static function overwrite($array1, $array2)
    {
        foreach (array_intersect_key($array2, $array1) as $key => $value)
        {
            $array1[$key] = $value;
        }

        if (func_num_args() > 2)
        {
            foreach (array_slice(func_get_args(), 2) as $array2)
            {
                foreach (array_intersect_key($array2, $array1) as $key => $value)
                {
                    $array1[$key] = $value;
                }
            }
        }

        return $array1;
    }

    /**
     *   list($func, $params) = Arr::callback('Foo::bar(apple,orange)');
     *   $result = call_user_func_array($func, $params);
     * @param type $str
     * @return type 
     */
    public static function callback($str)
    {
        $command = $params = NULL;

        if (preg_match('/^([^\(]*+)\((.*)\)$/', $str, $match))
        {
            $command = $match[1];

            if ($match[2] !== '')
            {
                $params = preg_split('/(?<!\\\\),/', $match[2]);
                $params = str_replace('\,', ',', $params);
            }
        }
        else
        {
            $command = $str;
        }

        if (strpos($command, '::') !== FALSE)
        {
            $command = explode('::', $command, 2);
        }

        return array($command, $params);
    }

    /**
     *  把多维数组转为一位数组
     *     $array = array('set' => array('one' => 'something'), 'two' => 'other');
     *     $array = Arr::flatten($array);
     *     array('one' => 'something', 'two' => 'other');
     * @param   array 
     * @return  array
     */
    public static function flatten($array)
    {
        $is_assoc = Arr::is_assoc($array);

        $flat = array();
        foreach ($array as $key => $value)
        {
            if (is_array($value))
            {
                $flat = array_merge($flat, Arr::flatten($value));
            }
            else
            {
                if ($is_assoc)
                {
                    $flat[$key] = $value;
                }
                else
                {
                    $flat[] = $value;
                }
            }
        }
        return $flat;
    }

    /**
     *  把数组data里面的键名 改为某个字段（数组里存在的）的值
     * @param type $key
     * @param type $data
     * @return type
     */
    public static function setkey($key, $data)
    {

        if (Arr::is_array($data) && count($data) > 0)
        {
            $temp = array();
            foreach ($data as $value)
            {
                $temp[$value[$key]] = $value;
            }

            if (count($temp) > 0)
            {
                return $temp;
            }
        }
        return array();
    }

    /**
     *   验证某个数组是否有效
     * @param type $data
     * @param type $key
     * @return type
     */
    public static function validate_arr($data, $key = FALSE)
    {
        if ($key === FALSE)
        {
            return isset($data) && count($data) > 0 && Arr::is_array($data);
        }
        return isset($data[$key]) && count($data[$key]) > 0 && Arr::is_array($data[$key]) ;
    }

    /**
     * 递归的得到多维数组中给定的键名的数据
     * @param type $data
     * @param type $k
     * @return type
     */
    public static function recursion_get_value($data, $k)
    {
        if (Arr::validate_arr($data))
        {
            foreach ($data as $value)
            {
                if (Arr::validate_arr($value))
                {
                    if (array_key_exists($k, $value))
                    {
                        return $value[$k];
                    }
                    else
                    {
                        if (Arr::validate_arr($value))
                        {
                            Arr::recursion_get_value($value, $k);
                        }
                    }
                }
            }
        }
    }
    
     /**
     * 递归的得到多维数组中给定的键名的数据(返回的是数组)
     * @param type $data
     * @param type $k
     * @return type
     */
    public static function recursion_get_value_arr($data, $k)
    {
        static $temp = array();
        if (Arr::validate_arr($data))
        {
            foreach ($data as $value)
            {
                if (Arr::validate_arr($value))
                {
                    if (array_key_exists($k, $value))
                    {
                        $temp[] = $value[$k];
                    }
                    else
                    {
                        if (Arr::validate_arr($value))
                        {
                            Arr::recursion_get_value($value, $k);
                        }
                    }
                }
            }
        }
        return $temp;
    }

    /**
     * 递归的得到多维数组中$k所在数组的键名
     * @param type $data
     * @param type $k
     * @return type
     */
    public static function recursion_get_key($data, $k)
    {
        if (Arr::validate_arr($data))
        {
            foreach ($data as $key => $value)
            {
                if (Arr::validate_arr($value))
                {
                    if (array_key_exists($k, $value))
                    {
                        return $key;
                    }
                    else
                    {
                        if (Arr::validate_arr($value))
                        {
                            Arr::recursion_get_key($value, $k);
                        }
                    }
                }
            }
        }
    }

}
